#!/usr/bin/python2.4


import os
import time
import urllib

import constants
from logger import logger
import rpc_stubs
import url
import utils


class JobHostRun(object):

  __slots__ = ('test_views',
               'job_idx_idx', 'test_job_idx_idx', 'host_job_idx_idx')

  def __init__(self, test_views):
    self.test_views = test_views

  def __repr__(self):
    return "%s '%s': %s" % (self.job_tag, self.test_job_name, self.status)

  def __getattr__(self, name):
    return getattr(self.test_views[0], name)

  def __getitem__(self, key):
    return self.test_views[key]

  @staticmethod
  def get_test_triage_info(test_view):
    return getattr(test_view, 'attributes', {}).get(constants.TA_TRIAGE_INFO)

  @staticmethod
  def set_test_triage_info(test_view, triage_info):
    attributes = getattr(test_view, 'attributes', None)
    if attributes is None:
      attributes = test_view.attributes = {}
    elif attributes is test_view.raw_object.get('attributes'):
      attributes = test_view.attributes = dict(attributes)
    attributes[constants.TA_TRIAGE_INFO] = triage_info

  @staticmethod
  def get_test_labels(test_view):
    return test_view.labels

  @staticmethod
  def set_test_label(test_view, label_to_set):
    labels = [label
              for label in test_view.labels
              if label not in constants.ALL_TL_LABELS]
    if label_to_set:
      labels.append(label_to_set)
    if test_view.labels != labels:
      test_view.labels = labels

  @property
  def test_job_name(self):
    return self.job_name.split(': ')[-1]

  @property
  def first_failed_test_view(self):
    for test_view in self.test_views or ():
      if test_view.status not in ('GOOD', 'RUNNING'):
        return test_view
    return None

  @property
  def status(self):
    # Returns 'RUNNING', 'GOOD', 'RESOLVED', 'FAIL', 'TRIAGE NEEDED',
    # 'TRIAGED' or 'INVALIDATED'
    if not self.job_finished_time:
      return 'RUNNING'
    if not self.test_views:
      parsed_time = utils.parse_time(self.job_finished_time)
      if time.time() - parsed_time > 24 * 60 * 60:
        return 'INVALIDATED'
      else:
        return 'TRIAGE NEEDED'
    for test_view in self.test_views:
      if test_view.status == 'RUNNING':
        return 'RUNNING'
      if test_view.status != 'GOOD':
        labels = self.get_test_labels(test_view)
        if constants.TL_INVALIDATED in labels:
          return 'INVALIDATED'
        if constants.TL_RESOLVED in labels:
          return 'RESOLVED'
        if constants.TL_NO_RERUN in labels:
          return 'FAIL'
        if self.get_test_triage_info(test_view):
          return 'TRIAGED'
        return 'TRIAGE NEEDED'
    if constants.TL_INVALIDATED in self.get_test_labels(self.test_views[0]):
      return 'INVALIDATED'
    return 'GOOD'

  @property
  def symptoms(self):
    reasons = []
    for test_view in self.test_views or ():
      reason = test_view.reason.strip()
      if reason and reason != 'completed successfully':
        reasons.append(reason.replace(self.hostname, '<hostname>'))
    return '; '.join(reasons)

  @property
  def jlog_runids(self):
    runids = []
    for test_view in self.test_views or ():
      for iteration in getattr(test_view, 'iterations', []):
        runid = iteration.get('attr', {}).get('jlog_run_id')
        if runid:
          runids.append(runid)
    return runids

  @property
  def running_time(self):
    parsed_times = {}
    for test_view in self.test_views or ():
      for job_time_type in ('queued', 'started', 'finished'):
        if job_time_type not in parsed_times:
          job_time = getattr(test_view, 'job_%s_time' % job_time_type)
          if job_time:
            parsed_times[job_time_type] = utils.parse_time(job_time)
      if test_view.status == 'RUNNING':
        now = time.time()
        return (now - parsed_times['started'], now - parsed_times['queued'])

    return (parsed_times['finished'] - parsed_times['started'],
            parsed_times['finished'] - parsed_times['queued'])

  @property
  def triage_info(self):
    triage_infos = []
    for test_view in self.test_views or ():
      triage_info = self.get_test_triage_info(test_view)
      if triage_info:
        triage_infos.append(triage_info)
    return '; '.join(triage_infos)

  def set_triage_info(self, triage_info, commit=False):
    if not self.test_views:
      logger.error("Unable to set triage info for '%s'" % self.job_tag)
      return False
    set_test_view = self.first_failed_test_view or self.test_views[0]
    if commit:
      rpc_stubs.tko.set_test_attribute(constants.TA_TRIAGE_INFO, triage_info,
                                       test_idx=set_test_view.test_idx)
    self.set_test_triage_info(set_test_view, triage_info)
    return True

  @property
  def labels(self):
    return (self.first_failed_test_view or self.test_views[0]).labels

  def set_label(self, label_to_set, must_fail=True, commit=False):
    set_test_view = self.first_failed_test_view
    if not set_test_view and not must_fail and self.test_views:
      set_test_view = self.test_views[0]
    if not set_test_view:
      logger.error("Unable to set label '%s' for '%s'" %
                   (label_to_set, self.job_tag))
      return False
    if commit:
      for label in constants.ALL_TL_LABELS:
        if label == label_to_set:
          rpc_stubs.tko.test_label_add_tests(label, job_tag=self.job_tag)
        else:
          rpc_stubs.tko.test_label_remove_tests(label, job_tag=self.job_tag)
    self.set_test_label(set_test_view, label_to_set)
    return True

  def mark_as_invalidated(self, commit=False):
    return self.set_label(constants.TL_INVALIDATED,
                          must_fail=False, commit=commit)

  def mark_as_resolved(self, commit=False):
    return self.set_label(constants.TL_RESOLVED,
                          must_fail=True, commit=commit)

  def mark_as_fail(self, commit=False):
    return self.set_label(constants.TL_NO_RERUN,
                          must_fail=True, commit=commit)

  def clear_labels(self, commit=False):
    return self.set_label(None, must_fail=False, commit=commit)

  def open_log_file(self, path):
    return urllib.urlopen(
        os.path.join(url.autotest_log_url(self.job_tag), path))

  def pformat(self, include_test_views=False):
    results = ["%s '%s': %s - '%s'" % (self.job_tag, self.test_job_name,
                                       self.status, self.symptoms)]
    if include_test_views:
      results.extend(' %s: %s %r' % (test_view.test_name,
                                     test_view.status,
                                     self.get_test_labels(test_view))
                     for test_view in self.test_views or ())
    return '\n'.join(results)
